#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define W_SIZE 1000
#define N_MAX 3000
#define N_PRIMES 367

/*
 * Vector with all the prime numbers from 2 to 3000
 * */
int PrimeNumbers[N_PRIMES];

/*
 * Function: ClearString
 * Params: char *String
 * Return: void
 * Clean the String received
 * */
void *ClearString(char *String);

/*
 * Function: CrivosAlgorithm
 * Param: void
 * Return: void
 * Calculates all the prime numbers from 2 to 2500.
 * The numbers are available to be consulted in the global vector PrimeNumbers*/
void CrivosAlgorithm();

/*
 * Function: isPrime
 * Param: char *String
 * return: int : 1 - TRUE; 0 - FALSE
 * The function will sum the ascii values of the String and check if this number is in the PrimeNumbers vector.
 * If it is, the function return TRUE (1) else return FALSE (0)*/
int isPrime(char *String);

/*
 * Function: isPalindrome
 * Param: char *String
 * return: int: 1 - TRUE; 0 - FALSE
 * The function will check is the String is a Palindrome
 * */
int isPalindrome(char *String);

/*
 * Function: inTheWord
 * Param: char c
 * return int: 1 _ TRUE; 0 - FALSE
 * Verify if the char is in the word
*/
int inTheWord(char c);

/*
 * Function: CountOnFile
 * Param: char *StringTemp, long int sizeFile, long int Numbers[]
 * Return: Void
 * The function count from the file f the number of Palindrome Words
 * and the number of words with ascii value equals a prime number*/
void CountOnFile(char *StringTemp, long int sizeFile, long int Numbers[]);

int main(){
    //Create and set the variables and open the input File
    long int counter[2] = {0,0};
    FILE *f = fopen("wikipedia.txt", "r");
	char *StringTemp;
	long int sizeFile;

    //Verify if the file oppened
    if(f == NULL){
        printf("Cannot open file\n");
        exit(-1);
    }
    else{
		//we create the string to load the whole file
		fseek (f , 0 , SEEK_END);
		sizeFile = ftell(f);
		rewind(f);
		StringTemp = (char*)malloc(sizeFile*sizeof(char));
		fread(StringTemp, sizeof(char), sizeFile, f);

        // Calculates the prime numbers
        CrivosAlgorithm();

		// Start the function
        CountOnFile(StringTemp, sizeFile, counter);

        printf("\nPalindromes found: %ld\nPrimes found:       %ld\n\n", counter[0], counter[1]);
        fclose(f);

    }
    return 0;
}

void *ClearString(char *String){
    //Gets the size of the string and change every char for a '\0'
    int i, size = strlen(String);
    for(i=0; i< size; i++){
        String[i] = '\0';
    }
}

void CrivosAlgorithm(){
    // We create the local variables and set the initial values
    int auxVector[N_MAX];
    int check = sqrt(N_MAX);
    int i;
    int aux=0;
    int inc =0;

    //Fill the auxVector with numbers from 2 to N_MAX+2
    for(i=0; i<N_MAX; i++){
        auxVector[i] = i+2;
    }

    //Eliminates the non-prime numbers (multiples of i)
    for(i=0; i<check; i++){
        if(auxVector[i] != 0){
            inc = auxVector[i];
            aux = i+inc;

            while(aux < N_MAX){
                if(auxVector[aux] != 0){
                    auxVector[aux] = 0;
                }
                aux += inc;
            }
        }
    }

    //Fill the Global Vector
    aux=0;
    for(i=0; i<N_MAX; i++){
        if(auxVector[i] >0){
            PrimeNumbers[aux] = auxVector[i];
            aux++;
        }
    }
}

int isPrime(char *String){
    int sum = 0;
    int i;

    //Sum the ASCII values from string
    for(i=0; i<strlen(String); i++){
        sum += String[i];

    }
    //Verify if the sum is in the Global Vector
    for(i=0; i<N_PRIMES; i++){
        if(PrimeNumbers[i] > sum){
            return 0;
        }
        else if(PrimeNumbers[i] == sum){
            return 1;
        }
    }
}

int isPalindrome(char *String){
    // We create the local variables and set the initial values
    char inverse_String[W_SIZE];
    int count, size = strlen(String);
    int i;

    long v = String[0];

    // If the String isn't just a letter, i.e: 'a', verify if its a palindrome
    if(strlen(String) > 1 && v != '\0'){
        //transform all the letters to lower chars
        for(i=0; i<size; i++){
            String[i] = tolower(String[i]);
        }

        count = size-1;
        ClearString(inverse_String);
        //copy the string to a aux string in the inverse
        for(i=0; i<size; i++){
            inverse_String[i] = String[count];
            count--;
        }
        //compare both strings
        if(strcmp(inverse_String, String) == 0){
            return 1;
        }
        else return 0;
    }
    else return 0;
}

int inTheWord(char c){
    //if the char is one of this symbols, its not the final of the word
    if(((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) || ((c >= '0') && (c <= '9')))
        return 1;

    else return 0;
}

void CountOnFile(char *StringTemp, long int sizeFile, long int Numbers[]){
    // Create and Set the variables and its initials values
    char Word[W_SIZE];
    char c;

    int i;
    long int counter=0;

    ClearString(Word);

    // For each char of the file, analyses if indicates an end of word
    for(i=0; i<sizeFile; i++){
        c = StringTemp[i];
        //If it is a letter or number, continue the analysis
        if( inTheWord(c) ){
            Word[counter] = c;
            counter++;
        }
        else{
            //Verify if the word is a palindrome
            if(isPalindrome(Word) && strlen(Word) > 1){
                Numbers[0]++;
		        //verify if the sum of the ascii values is a prime number
		        if(isPrime(Word) && strlen(Word)){
		            Numbers[1]++;
		        }
            }

            ClearString(Word);
            counter=0;
        }
    }
    ClearString(StringTemp);
}

